"use client"; import { Link } from "@/i18n/navigation"; import { useEffect, useMemo, useState } from "react"; import { ArrowLeft, Loader2, Wallet, CheckCircle2, AlertCircle } from "lucide-react"; import { fetchWalletBalance } from "@/lib/account-api"; import { fetchWithdrawBankOptions, fetchWithdrawChannels, submitWithdrawApply, type SavedWithdrawAccount, type WithdrawBankOption, type WithdrawChannel, } from "@/lib/withdrawal-api"; import { cn } from "@/lib/utils"; // 保留原有的所有辅助函数 (channelGroupLabel, groupOrder, formatAmountRange 等) function channelGroupLabel(channel: WithdrawChannel): string { const type = channel.type; const code = (channel.code || "").toUpperCase(); const name = `${channel.name || ""} ${channel.enName || ""}`.toUpperCase(); const aliHint = code.includes("ALI") || code.includes("ALIPAY") || name.includes("ALIPAY"); if (type === "BANK_TELEGRAPHIC") return "国际转账"; if (type === "BANK") return "网银支付"; if (type === "DIGITAL_CURRENCY") return "数字货币"; if (type === "CHANNEL_TYPE_WALLET") return "电子钱包"; if (type === "CHANNEL_TYPE_CARD") return "信用卡"; if (type === "CHANNEL_TYPE_ALI_WALLET" || aliHint) return "支付宝"; if (type === "UCARD_WALLET") return "电子卡"; return "其他"; } function groupOrder(label: string): number { if (label === "数字货币") return 1; if (label === "网银支付") return 2; if (label === "国际转账") return 3; if (label === "电子钱包") return 4; if (label === "电子卡") return 5; if (label === "支付宝") return 6; return 99; } function formatAmountRange(item: WithdrawChannel): string { const min = item.minAmount || 0; const max = item.maxAmount > 0 ? item.maxAmount : "-"; return `$${min} - $${max} ${item.currency || "USD"}`; } function formatFee(item: WithdrawChannel): string { if (item.feeType === 1) return `${item.free ?? 0}%`; if (item.feeType === 2) return `$${item.feeAmount ?? 0}`; if (item.free !== null && item.free !== undefined) return `${item.free}%`; return "0%"; } function sanitizeHtml(input: string): string { if (!input) return ""; return input.replace(/[\s\S]*?<\/script>/gi, "").replace(/\son\w+="[^"]*"/gi, "").replace(/\son\w+='[^']*'/gi, ""); } function isWalletType(type: string) { return type === "CHANNEL_TYPE_WALLET" || type === "CHANNEL_TYPE_ALI_WALLET"; } function isBankType(type: string) { return type === "BANK"; } function isCardType(type: string) { return type === "CHANNEL_TYPE_CARD"; } function isDigitalCurrencyType(type: string) { return type === "DIGITAL_CURRENCY"; } function savedAccountType(type: string): number | null { if (type === "BANK") return 1; if (type === "BANK_TELEGRAPHIC") return 2; if (type === "CHANNEL_TYPE_CARD") return 3; if (type === "DIGITAL_CURRENCY") return 4; return null; } export default function WithdrawApplyPage() { const [channels, setChannels] = useState([]); const [channelsLoading, setChannelsLoading] = useState(false); const [channelsError, setChannelsError] = useState(null); const [walletBalance, setWalletBalance] = useState(null); const [savedAccounts] = useState([]); const [bankOptions, setBankOptions] = useState([]); // 表单状态 const [selectedChannelId, setSelectedChannelId] = useState(""); const [selectedSavedId, setSelectedSavedId] = useState(""); const [selectedBankCode, setSelectedBankCode] = useState(""); const [addressName, setAddressName] = useState(""); const [address, setAddress] = useState(""); const [amount, setAmount] = useState(""); const [agree, setAgree] = useState(false); const [agreeExtra, setAgreeExtra] = useState(false); // ... 其他银行/电汇字段 const [agencyNo, setAgencyNo] = useState(""); const [cpf, setCpf] = useState(""); const [bankUnameInput, setBankUnameInput] = useState(""); const [bankCardNumInput, setBankCardNumInput] = useState(""); const [bankNameInput, setBankNameInput] = useState(""); const [bankBranchNameInput, setBankBranchNameInput] = useState(""); const [swiftCodeInput, setSwiftCodeInput] = useState(""); const [customBankCodeInput, setCustomBankCodeInput] = useState(""); const [bankAddrInput, setBankAddrInput] = useState(""); const [telegraphicCurrency, setTelegraphicCurrency] = useState("USD"); const [cardUnameInput, setCardUnameInput] = useState(""); const [cardNumInput, setCardNumInput] = useState(""); const [cardCvvInput, setCardCvvInput] = useState(""); const [cardExpiryInput, setCardExpiryInput] = useState(""); const [submitting, setSubmitting] = useState(false); const [confirmOpen, setConfirmOpen] = useState(false); const [expandedGroup, setExpandedGroup] = useState("数字货币"); const [applyDialogOpen, setApplyDialogOpen] = useState(false); const [resultDialog, setResultDialog] = useState({ open: false, status: "success", title: "", message: "" }); const selectedChannel = useMemo(() => channels.find((item) => item.id === selectedChannelId) ?? null, [channels, selectedChannelId]); const selectedSavedAccount = useMemo(() => savedAccounts.find((item) => item.id === selectedSavedId) ?? null, [savedAccounts, selectedSavedId]); const filteredSavedAccounts = useMemo(() => { if (!selectedChannel) return []; const type = savedAccountType(selectedChannel.type); if (type === null) return []; return savedAccounts.filter((item) => item.type === type); }, [savedAccounts, selectedChannel]); const shouldRequireSavedAccount = false; const shouldShowSavedAccountSelector = shouldRequireSavedAccount && filteredSavedAccounts.length > 0; const isBankTelegraphic = selectedChannel?.type === "BANK_TELEGRAPHIC"; const needCpf = selectedChannel?.code === "PAY_RETAILER_REMIT_PAY_KEY_BRW"; function resetApplyForm() { setSelectedSavedId(""); setSelectedBankCode(""); setAddressName(""); setAddress(""); setAmount(""); setAgree(false); setAgreeExtra(false); setAgencyNo(""); setCpf(""); setBankUnameInput(""); setBankCardNumInput(""); setBankNameInput(""); setBankBranchNameInput(""); setSwiftCodeInput(""); setCustomBankCodeInput(""); setBankAddrInput(""); setTelegraphicCurrency("USD"); setCardUnameInput(""); setCardNumInput(""); setCardCvvInput(""); setCardExpiryInput(""); } useEffect(() => { let cancelled = false; async function loadBase() { setChannelsLoading(true); setChannelsError(null); try { const [balanceResult, channelsResult] = await Promise.all([fetchWalletBalance(), fetchWithdrawChannels()]); if (cancelled) return; setWalletBalance(balanceResult); setChannels(channelsResult); } catch (e) { if (!cancelled) setChannelsError((e as Error)?.message || "通道加载失败"); } finally { if (!cancelled) setChannelsLoading(false); } } void loadBase(); return () => { cancelled = true; }; }, []); useEffect(() => { if (!selectedChannel || !applyDialogOpen) { setBankOptions([]); setSelectedBankCode(""); return; } resetApplyForm(); if (!selectedChannel.bankValid) return; let cancelled = false; async function loadBankOptions() { try { const list = await fetchWithdrawBankOptions(selectedChannel!.code); if (cancelled) return; setBankOptions(list); setSelectedBankCode((prev) => prev || list[0]?.code || ""); } catch { if (!cancelled) setBankOptions([]); } } void loadBankOptions(); return () => { cancelled = true; }; }, [selectedChannel, applyDialogOpen]); useEffect(() => { if (!selectedSavedAccount) return; if (!isBankType(selectedChannel?.type || "") && !isBankTelegraphic) return; setBankUnameInput(selectedSavedAccount.bankUname || ""); setBankCardNumInput(selectedSavedAccount.bankCardNum || ""); setBankNameInput(selectedSavedAccount.bankName || ""); setBankBranchNameInput(selectedSavedAccount.bankBranchName || ""); setSwiftCodeInput(selectedSavedAccount.swiftCode || ""); setCustomBankCodeInput(selectedSavedAccount.customBankCode || ""); setBankAddrInput(selectedSavedAccount.bankAddr || ""); }, [selectedSavedAccount, selectedChannel?.type, isBankTelegraphic]); function validate(): string | null { if (!selectedChannel) return "请选择领取通道"; if (!/^[0-9]+([.][0-9]{1,2})?$/.test(amount.trim())) return "请输入正确的领取金额"; const amountNum = Number(amount); if (!Number.isFinite(amountNum) || amountNum <= 0) return "金额必须大于0"; if (selectedChannel.minAmount > 0 && amountNum < selectedChannel.minAmount) return `不能低于 ${selectedChannel.minAmount}`; if (selectedChannel.maxAmount > 0 && amountNum > selectedChannel.maxAmount) return `不能高于 ${selectedChannel.maxAmount}`; if (isWalletType(selectedChannel.type) && !address.trim()) return "请填写领取地址"; if (isDigitalCurrencyType(selectedChannel.type)) { if (!addressName.trim()) return "请填写区块链名称"; if (!address.trim()) return "请填写钱包地址"; } if (isBankType(selectedChannel.type)) { if (!bankUnameInput.trim()) return "请输入户名"; if (!bankCardNumInput.trim()) return "请输入卡号"; if (!bankNameInput.trim()) return "请输入银行名称"; if (!bankBranchNameInput.trim()) return "请输入支行"; } if (isBankTelegraphic) { if (!swiftCodeInput.trim() || !bankAddrInput.trim()) return "请完善电汇信息"; } if (!agree) return "请同意领取条款"; if (!agreeExtra) return "请确认信息无误"; return null; } async function doSubmit() { if (!selectedChannel) return; const payload: Record = { payType: selectedChannel.code, amount: Number(amount), currency: selectedChannel.type === "BANK_TELEGRAPHIC" ? "USD" : selectedChannel.currency, agree2: true }; // ... 组装 payload 的逻辑保持原样 if (address.trim()) payload.address = address.trim(); if (addressName.trim()) payload.addressName = addressName.trim(); if (isBankType(selectedChannel.type)) { payload.bankUname = bankUnameInput; payload.bankCardNum = bankCardNumInput; payload.bankName = bankNameInput; payload.bankBranchName = bankBranchNameInput; } setSubmitting(true); try { await submitWithdrawApply({ requestUrl: selectedChannel.requestUrl, payload }); setResultDialog({ open: true, status: "success", title: "提交成功", message: "申请已提交审核。" }); resetApplyForm(); } catch (e) { setResultDialog({ open: true, status: "error", title: "提交失败", message: (e as Error).message }); } finally { setSubmitting(false); setConfirmOpen(false); } } const channelGroups = useMemo(() => { const groups: Record = {}; for (const item of channels) { const key = channelGroupLabel(item); if (!groups[key]) groups[key] = []; groups[key].push(item); } return Object.entries(groups).sort((a, b) => groupOrder(a[0]) - groupOrder(b[0])); }, [channels]); // 表单通用 Input 组件 const InputCls = "mt-2 w-full rounded-xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-white placeholder-slate-500 focus:border-[#b89458] focus:outline-none focus:ring-1 focus:ring-[#b89458]"; return (

发起领取申请

当前可领取余额: ${(walletBalance ?? 0).toFixed(2)}

返回控制中心

选择提款通道

{channelsLoading ?
: null} {channelsError ?

{channelsError}

: null}
{channelGroups.map(([group, items]) => (
{expandedGroup === group && (
{items.map((item) => ( ))}
通道类型 限额 手续费 操作
{item.icon ? :
} {item.name || item.code}
{formatAmountRange(item)} {formatFee(item)}
)}
))}
{/* 填写表单大弹窗 */} {applyDialogOpen && selectedChannel && (

填写提款信息

{/* 提示信息 */}
当前通道: {selectedChannel.name || selectedChannel.code}
{/* 表单渲染区域 */}
{isDigitalCurrencyType(selectedChannel.type) && (
setAddressName(e.target.value)} />
setAddress(e.target.value)} />
)} {isBankType(selectedChannel.type) && (
setBankUnameInput(e.target.value)} />
setBankCardNumInput(e.target.value)} />
setBankNameInput(e.target.value)} />
setBankBranchNameInput(e.target.value)} />
)} {/* 金额 */}
$ setAmount(e.target.value)} />
{/* 条款 */}
)} {/* 二次确认弹窗 */} {confirmOpen && (

即将发起提款

${amount}

请再次确认信息无误,提交后将进入人工审核队列。

)} {/* 结果弹窗 */} {resultDialog.open && (
{resultDialog.status === 'success' ? : }

{resultDialog.title}

{resultDialog.message}

)}
); }